------------------------------------------------------------------------------------
-- base/core.lua
--
-- 本模块是整个框架的核心，整个脚本的入口，管理和加载所有模块、各种回调函数的调用等。
--
-- @module      core
-- @author      admin
-- @license     MIT
-- @release     v1.0.0 - 2023-03-22
-- @copyright   2023
------------------------------------------------------------------------------------

-- 模块定义
---@class core
local core         = {
    -- 模块版本 (主版本.次版本.修订版本)
    VERSION              = '1.0.0',
    -- 作者备注 (更新日期 - 更新内容简述)
    AUTHOR_NOTE          = '2024-04-27 - Initial release',
    -- 模块名称
    MODULE_NAME          = 'core module',
    -- 只读模式
    READ_ONLY            = false,

    -- 轮循计时器ID
    CIRCULAR_TIMER_ID    = 88888,
    -- 轮循间隔10秒
    CIRCULAR_TIMER_DELAY = 10000
}

-- 实例对象
local this         = core

-------------------------------------------------------------------------------------
-- 导入所有模块

-- 全局设置
_G.settings        = import('base/settings')
-- 杂项模块
_G.utils           = import('base/utils')
-- 日志模块
_G.trace           = import('base/trace')
-- 决策模块
_G.decider         = import('base/decider')
-- 监控模块
_G.monitor         = import('game/monitor')
-- 监控模块
_G.common          = import('game/entities/common')
-- 文本操作
_G.configer        = import('base/configer')
-------------------------------------------------------------------------------------

-- 模块列表
core.module_list   = import('game/modules')

-------------------------------------------------------------------------------------
-- 优化列表

local os           = os
local math         = math
local table        = table
local xpcall       = xpcall
local sleep        = sleep
local ipairs       = ipairs
local pairs        = pairs
local setmetatable = setmetatable
local is_working   = is_working
local main_ctx     = main_ctx
local killtimer    = killtimer
local settings     = settings
local trace        = trace
---@type decider
local decider      = decider
local monitor      = monitor
local rawset       = rawset
local error        = error

-------------------------------------------------------------------------------------
-- 验证 core.module_list 中所有模块的配置完整性。
-- @local
-------------------------------------------------------------------------------------
function core.validate_modules()
    local priority_set    = {} -- 用于存储所有模块的 priority 以检查重复
    local module_name_set = {} -- 用于检查模块名的重复

    for _, module in ipairs(this.module_list) do
        -- 检查模块名称是否重复
        local module_name = module.MODULE_NAME or "未命名模块"
        if module_name_set[module_name] then
            error("配置错误: 模块名称重复 {" .. module_name .. "}")
        else
            module_name_set[module_name] = true
        end

        -- 检查 eval_ifs 配置
        local eval_ifs = module.eval_ifs
        local missing_items = {} -- 用于记录缺失的配置项

        if not eval_ifs then
            table.insert(missing_items, "eval_ifs")
        else
            if not eval_ifs.yes_game_state then table.insert(missing_items, "eval_ifs.yes_game_state") end
            if not eval_ifs.not_game_state then table.insert(missing_items, "eval_ifs.not_game_state") end
            if not eval_ifs.yes_config then table.insert(missing_items, "eval_ifs.yes_config") end
            if not eval_ifs.not_config then table.insert(missing_items, "eval_ifs.not_config") end
            if eval_ifs.time_out == nil then table.insert(missing_items, "eval_ifs.time_out") end
            if not eval_ifs.is_working then table.insert(missing_items, "eval_ifs.is_working") end
            if not eval_ifs.is_execute then table.insert(missing_items, "eval_ifs.is_execute") end
            if not eval_ifs.priority then table.insert(missing_items, "eval_ifs.priority") end
            if not eval_ifs.can_interrupt then table.insert(missing_items, "eval_ifs.can_interrupt") end
            if not eval_ifs.is_started then table.insert(missing_items, "eval_ifs.is_started") end
        end

        -- 检查模块是否定义了入口函数
        if not module.entry then
            table.insert(missing_items, "entry")
        end

        -- 如果有缺失的项或未定义入口函数，报告错误
        if #missing_items > 0 then
            error("配置错误: 模块 {" .. module_name .. "} 缺少必要的配置项：" .. table.concat(missing_items, ", "))
        end

        -- 检查 priority 是否重复
        -- if eval_ifs and eval_ifs.priority then
        --    local priority = eval_ifs.priority()
        --    if priority_set[priority] then
        --    error("配置错误: 发现重复的 priority " .. priority .. " 在模块 {" .. priority_set[priority] .. "} 和 {" .. module_name .. "}")
        --    else
        --       priority_set[priority] = module_name
        --    end
        -- end
    end
end

-------------------------------------------------------------------------------------
-- 预载处理(重载脚本)
-- @local
-------------------------------------------------------------------------------------
function core.super_preload()
    -- 关闭自动重启
    main_ctx:auto_restart(false)
    -- 验证 core.module_list 中所有模块的配置完整性
    this.validate_modules()
    -- 根据优先级排序
    table.sort(this.module_list, function(a, b)
        return a.eval_ifs.priority() < b.eval_ifs.priority()
    end)
    local new_module = {}
    -- 初始化所有模块
    for _, module in ipairs(this.module_list)
    do
        --标识为离开状态
        module.should_exit = true
        -- 标识为未超时状态
        module.timeout_state = false
        module.entry_count = 0
        module.entry_time = 0
        module.leave_time = 0
        module.last_occupy_duration = 0
        module.total_occupy_duration = 0
        table.insert(new_module, module)
    end
    -- 设置模块列表
    decider.set_module_list(new_module)
end

-------------------------------------------------------------------------------------
-- 预载处理(脚本运行)
-------------------------------------------------------------------------------------
function core.preload()
    -- 这个必须保留
    sleep(100)
    -- 开启自动重启
    main_ctx:auto_restart(true)
    -- 初始化所有模块
    for k, v in ipairs(this.module_list) do
        -- 调用功能
        if v.preload then
            -- v.preload()
            xpcall(v.preload, this.error_handler)
        end
    end
    -- 初始化监控模块
    xpcall(monitor.preload, this.error_handler)
    -- 安装轮循计时器
    -- settimer(this.CIRCULAR_TIMER_ID, this.CIRCULAR_TIMER_DELAY)
end

-------------------------------------------------------------------------------------
-- 入口函数(主循环)
-------------------------------------------------------------------------------------
function core.entry()
    -- 设置随机数种子
    math.randomseed(os.time())

    -- 寻找最高优先级的模块并执行
    local modules, no_run_module = decider.find_highest_priority_modules()
    if #modules > 0 then
        local module = modules[1]
        -- 设置当前上下文
        decider.set_curr_context(module)
        -- 调用功能入口函数
        xpcall(decider.entry, this.error_handler)
        -- 清空当前上下文
        decider.set_curr_context(nil)
    else
        decider.put_no_module_msg(no_run_module)
    end
end

-------------------------------------------------------------------------------------
-- 定时回调(定时回调)
--
-- @tparam       integer   timer_id         定时器id
-- @usage
-- settimer(1, 1000) -- 设置定时器
-------------------------------------------------------------------------------------
function core.on_timer(timer_id)
    for k, v in ipairs(this.module_list) do
        -- 中断检测
        if not is_working() then
            break
        end
        -- 调用功能
        if v.on_timer then
            xpcall(v.on_timer, this.error_handler, timer_id)
        end
    end
end

-------------------------------------------------------------------------------------
-- 卸载处理(退出脚本)
-- @local
-------------------------------------------------------------------------------------
function core.unload()
    -- 卸载轮循计时器
    -- killtimer(this.CIRCULAR_TIMER_ID)
    -- 关闭自动重启
    main_ctx:auto_restart(false)
    -- 卸载所有模块
    xpcall(monitor.unload, this.error_handler)
    for k, v in ipairs(this.module_list) do
        -- 调用功能
        if v.unload then
            -- v.unload()
            xpcall(v.unload, this.error_handler)
        end
    end
end

-------------------------------------------------------------------------------------
-- 异常捕获函数
--
-- @local
-- @tparam       any       err              异常信息
-------------------------------------------------------------------------------------
function core.error_handler(err)
    -- 设置脚本终止标志
    if not settings.continue_on_error then
        set_exit_state(true)
    end
    trace.log_error(debug.traceback('error: ' .. tostring(err), 2))
end

------------------------------------------------------------------------------------
-- 将对象转换为字符串
--
-- @local
-- @treturn      string                     模块名称
------------------------------------------------------------------------------------
function core.__tostring()
    return this.MODULE_NAME
    -- -- 计算最大长度
    -- local max_key_length = 0
    -- for key, _ in pairs(this) do
    --    if key ~= '__tostring' then
    --       max_key_length = math.max(max_key_length, #key)
    --    end
    -- end
    -- -- 添加头部信息
    -- local fmt = '%-' .. (max_key_length + 1) .. 's: %s\n'
    -- local mode_str = this.READ_ONLY and 'Read-Only' or 'Read/Write'
    -- local str = string.format(fmt, 'Pointer', tostring(this))
    -- str = str .. string.format(fmt, 'Name', this.MODULE_NAME)
    -- str = str .. string.format(fmt, 'Version', this.VERSION)
    -- str = str .. string.format(fmt, 'Author', this.AUTHOR_NOTE)
    -- str = str .. string.format(fmt, 'Mode', mode_str)
    -- str = str .. '\nMembers:\n'
    -- -- 添加成员信息
    -- for key, value in pairs(this) do
    --    if key ~= '__tostring' then
    --       str = str .. string.format(fmt, key, tostring(value))
    --    end
    -- end
    -- -- 返回结果
    -- return str
end

------------------------------------------------------------------------------------
-- 防止动态修改(this.READ_ONLY值控制)
--
-- @local
-- @tparam       table     t                被修改的表
-- @tparam       any       k                要修改的键
-- @tparam       any       v                要修改的值
------------------------------------------------------------------------------------
function core.__newindex(t, k, v)
    if this.READ_ONLY then
        error('attempt to modify read-only table')
        return
    end
    rawset(t, k, v)
end

------------------------------------------------------------------------------------
-- 设置core的__index元方法指向自身
--
-- @local
------------------------------------------------------------------------------------
core.__index = core

------------------------------------------------------------------------------------
-- 创建一个新的实例
--
-- @local
-- @tparam       table     args             可选参数，用于初始化新实例
-- @treturn      table                      新创建的实例
------------------------------------------------------------------------------------
function core:new(args)
    local new = {}
    -- 预载函数(重载脚本时)
    if this.super_preload then
        this.super_preload()
    end
    -- 将args中的键值对复制到新实例中
    if args then
        for key, val in pairs(args) do
            new[key] = val
        end
    end
    -- 设置元表
    return setmetatable(new, core)
end

-------------------------------------------------------------------------------------
-- 返回实例对象
-------------------------------------------------------------------------------------
return core:new()

-------------------------------------------------------------------------------------
